﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.ServiceModel;
using System.Collections.ObjectModel;
using WcfContrib.Client.Behaviors;

namespace WcfContrib.Client.Description
{
    /// <summary>
    /// Represents a client channel operation description
    /// </summary>
	public sealed class ClientOperationDescription
	{
        /// <summary>
        /// Gets the name of the operation.
        /// </summary>
        /// <value>The name of the operation.</value>
		public string OperationName { get; private set; }
        /// <summary>
        /// Gets or sets a value indicating whether the operation uses asynchrnous pattern.
        /// </summary>
        /// <value><c>true</c> if [async pattern]; otherwise, <c>false</c>.</value>
		public bool AsyncPattern { get; private set; }
        /// <summary>
        /// Gets the method.
        /// </summary>
        /// <value>The method.</value>
		public MethodBase Method { get; private set; }

        /// <summary>
        /// Gets the operation invokers.
        /// </summary>
        /// <value>The operation invokers.</value>
		public DescriptionCollection<IClientOperationInvokerBehavior> Invokers { get; private set; }
        /// <summary>
        /// Gets the operation inspectors.
        /// </summary>
        /// <value>The operation inspectors.</value>
		public DescriptionCollection<IClientOperationInspectorBehavior> Inspectors { get; private set; }

        /// <summary>
        /// Gets the operation behaviors.
        /// </summary>
        /// <value>The operation behaviors.</value>
		public DescriptionCollection<IClientOperationBehavior> Behaviors { get; private set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="ClientOperationDescription"/> class.
        /// </summary>
		public ClientOperationDescription()
		{
			Invokers = new DescriptionCollection<IClientOperationInvokerBehavior>();
			Inspectors = new DescriptionCollection<IClientOperationInspectorBehavior>();
			Behaviors = new DescriptionCollection<IClientOperationBehavior>();
		}

		internal ClientOperationDescription CloneCore()
		{
			ClientOperationDescription desc = new ClientOperationDescription();

			desc.Inspectors.AddRange(Inspectors);
			desc.Invokers.AddRange(Invokers);
			desc.Behaviors.AddRange(Behaviors);
			desc.OperationName = OperationName;
			desc.Method = Method;
			desc.AsyncPattern = AsyncPattern;

			desc.Behaviors.ItemAdded = b => b.ApplyClientBehavior(desc);

			return desc;
		}

		internal void LoadOperation(OperationContractAttribute oper, MethodBase method)
		{
			OperationName = string.IsNullOrEmpty(oper.Name) ? method.Name : oper.Name;
			Method = method;
			AsyncPattern = oper.AsyncPattern;

			LoadMethod(method);
		}

		internal void LoadMethod(MethodBase method)
		{
			var operBehaviors = method.GetCustomAttributes(true).Where(o => o is IClientOperationBehavior).OfType<IClientOperationBehavior>();
			Behaviors.AddRange(operBehaviors, false);
		}

		internal void OnLoadComplete()
		{
			foreach (var behavior in Behaviors)
			{
				behavior.ApplyClientBehavior(this);
			}
		}
	}
}
